﻿
using CSharpLibs.Annotations;

#pragma warning disable 0169
#pragma warning disable 0649

//The version of the container to use when the container class has overridden the equals or hashcode methods.
namespace System.Collections.Generic
{
	[Builtin, Dictionary, Container, BuiltinImplementation]
	public sealed class Dictionary<K, V> : Object, IDictionary<K, V>, ICollection<KeyValuePair<K, V>>, IEnumerable<KeyValuePair<K, V>>, ICollection, IEnumerable
	{
		private int card;
		private int capacity;

		[MultiLocationField]
		private int allh;

		[MultiLocationField]
		private KeyValuePair<K, V> allf;

		[BuiltinMethod, BuiltinSemantics("dictionary_init")]
		public Dictionary()
		{ ;}

		public Dictionary(IDictionary<K, V> dictionary)
			: this()
		{
			Enumerator kvpe = new Enumerator(this);
			while(kvpe.MoveNext())
			{
				KeyValuePair<K, V> kvp = kvpe.Current;
				this.Add(kvp.Key, kvp.Value);
			}
		}

		[DoNotClearCollectionPosition]
		public void Add(K key, V value)
		{
			this.ReAllocateInternalTableAsNeeded();
			int matchpos = this.TablePosFor(key);

			if(this.GetHashAndValidForIndex(matchpos) < 0)
			{
				int hash = HashForStore(key);
				this.DoSetAdd(matchpos, hash, new KeyValuePair<K, V>(key, value));
			}
		}

		[BuiltinMethod, DoNotClearCollectionPosition, BuiltinSemantics("dictionary_adddirect")]
		private void DoSetAdd(int pos, int hash, KeyValuePair<K, V> value)
		{ ;}

		[BuiltinMethod, BuiltinSemantics("dictionary_clear")]
		public void Clear()
		{ ;}

		public bool ContainsKey(K key)
		{
			int matchpos = this.TablePosFor(key);
			return this.GetHashAndValidForIndex(matchpos) >= 0;
		}

		public bool ContainsValue(V value)
		{
			for(int i = 0; i < this.capacity; ++i)
			{
				if(this.GetHashAndValidForIndex(i) >= 0)
				{
					if(EqualityComparer<V>.DefaultEquals(value, this.GetValueAtIndex(i).Value))
						return true;
				}
			}

			return false;
		}

		private void CopyTo(KeyValuePair<K, V>[] array, int index)
		{
			int j = index;
			for(int i = 0; i < this.capacity; i++)
			{
				if(this.GetHashAndValidForIndex(i) >= 0)
					array[j++] = this.GetValueAtIndex(i);
			}
		}

		public Enumerator GetEnumerator()
		{ return new Enumerator(this); }

		public bool Remove(K key)
		{
			int matchpos = this.TablePosFor(key);
			if(this.GetHashAndValidForIndex(matchpos) < 0)
				return false;

			this.RemoveAt(matchpos);
			return true;
		}

		[BuiltinMethod, BuiltinSemantics("dictionary_removeatdirect")]
		private void RemoveAt(int pos)
		{ ;}

		[DoNotClearCollectionPosition]
		void ICollection<KeyValuePair<K, V>>.Add(KeyValuePair<K, V> kvp)
		{
			this.ReAllocateInternalTableAsNeeded();
			int matchpos = this.TablePosFor(kvp.Key);

			if(this.GetHashAndValidForIndex(matchpos) < 0)
			{
				int hash = HashForStore(kvp.Key);
				this.DoSetAdd(matchpos, hash, kvp);
			}
		}

		bool ICollection<KeyValuePair<K, V>>.Contains(KeyValuePair<K, V> kvp)
		{
			int matchpos = this.TablePosFor(kvp.Key);
			return this.GetHashAndValidForIndex(matchpos) >= 0;
		}

		void ICollection<KeyValuePair<K, V>>.CopyTo(KeyValuePair<K, V>[] array, int index)
		{
			int j = index;
			for(int i = 0; i < this.capacity; i++)
			{
				if(this.GetHashAndValidForIndex(i) >= 0)
					array[j++] = this.GetValueAtIndex(i);
			}
		}

		bool ICollection<KeyValuePair<K, V>>.Remove(KeyValuePair<K, V> kvp)
		{
			int matchpos = this.TablePosFor(kvp.Key);
			if(this.GetHashAndValidForIndex(matchpos) < 0)
				return false;

			this.RemoveAt(matchpos);
			return true;
		}

		IEnumerator<KeyValuePair<K, V>> IEnumerable<KeyValuePair<K, V>>.GetEnumerator()
		{ return new Enumerator(this); }

		IEnumerator IEnumerable.GetEnumerator()
		{ return new Enumerator(this); }

		public int Count
		{
			[BuiltinMethod, BuiltinSemantics("dictionary_getcount")]
			get { return -1; }
		}
		
		[BuiltinMethod, DoNotClearCollectionPosition, BuiltinSemantics("dictionary_gethvalid")]
		internal int GetHashAndValidForIndex(int i)
		{ return -1; }

		[BuiltinMethod, BuiltinSemantics("dictionary_getvalue"), CollectionGetterIndex]
		internal KeyValuePair<K,V> GetValueAtIndex(int i)
		{ return new KeyValuePair<K,V>(); }

		private static int HashForStore(K item)
		{
			if(item == null)
				return 0;

			int bhash = item.GetHashCode();
			return bhash & 0x7fffffff;
		}

		[DoNotClearCollectionPosition]
		internal int TablePosFor(K item)
		{
			int hash;
			if(item == null)
				hash = 0;
			else
			{
				int bhash = item.GetHashCode();
				hash = bhash & 0x7fffffff;
			}

			int pos = hash % this.capacity;

			if(this.GetHashAndValidForIndex(pos) < 0)
				return pos;

			if((this.GetHashAndValidForIndex(pos) == hash) && EqualityComparer<K>.DefaultEquals(item, this.GetValueAtIndex(pos).Key))
				return pos;

			int i = (pos + 1) % this.capacity;
			while(true)
			{
				if(this.GetHashAndValidForIndex(i) < 0)
					return i;

				if((this.GetHashAndValidForIndex(i) == hash) && EqualityComparer<K>.DefaultEquals(item, this.GetValueAtIndex(i).Key))
					return i;

				i = (i + 1) % this.capacity;
			}
		}

		[BuiltinMethod, DoNotClearCollectionPosition, BuiltinSemantics("dictionary_resizeasneeded")]
		private void ReAllocateInternalTableAsNeeded()
		{ ;}

		public V this[K key]
		{
			get
			{
				int matchpos = this.TablePosFor(key);
				return this.GetValueAtIndex(matchpos).Value;
			}

			[DoNotClearCollectionPosition]
			set
			{
				int matchpos = this.TablePosFor(key);
				int hash = HashForStore(key);
				this.DoSetAdd(matchpos, hash, new KeyValuePair<K, V>(key, value));
			}
		}

		public ICollection<K> Keys
		{ get { return new KeyCollection(this); } }

		public ICollection<V> Values
		{ get { return new ValueCollection(this); } }

		[Builtin, Enumerator]
		public struct Enumerator : IEnumerator<KeyValuePair<K, V>>, IDisposable, IEnumerator
		{
			[EnumeratorCollectionField]
			private Dictionary<K, V> dictionary;
		
			private int index;
			
			internal Enumerator(Dictionary<K, V> dictionary)
			{
				this.dictionary = dictionary;
				this.index = -1;
			}

			[EnumeratorAdvance]
			public bool MoveNext()
			{
				if(this.index < this.dictionary.capacity)
					this.index++;

				while(this.index < this.dictionary.capacity)
				{
					if(this.dictionary.GetHashAndValidForIndex(this.index) >= 0)
						return true;

					this.index++;
				}

				return false;
			}

			public KeyValuePair<K, V> Current
			{ 
				[EnumeratorGetterDictionary]
				get { return this.dictionary.GetValueAtIndex(this.index); } 
			}
			
			public void Dispose()
			{ ;}

			object IEnumerator.Current
			{ get { return this.dictionary.GetValueAtIndex(this.index); } }

			void IEnumerator.Reset()
			{ this.index = -1; }
		}

		[Builtin]
		public sealed class KeyCollection : ICollection<K>, IEnumerable<K>, ICollection, IEnumerable
		{
			// Fields
			private Dictionary<K, V> kdictionary;

			// Methods
			public KeyCollection(Dictionary<K, V> dictionary)
			{ this.kdictionary = dictionary; }

			public void CopyTo(K[] array, int index)
			{
				Enumerator ev = new Enumerator(this.kdictionary);
				int j = index;

				while(ev.MoveNext())
					array[j++] = ev.Current;
			}

			public Enumerator GetEnumerator()
			{ return new Enumerator(this.kdictionary); }

			void ICollection<K>.Add(K item)
			{ Environment.Exit(1); }

			void ICollection<K>.Clear()
			{ Environment.Exit(1); }

			bool ICollection<K>.Contains(K item)
			{ return this.kdictionary.ContainsKey(item); }

			bool ICollection<K>.Remove(K item)
			{
				Environment.Exit(1);
				return false;
			}

			IEnumerator<K> IEnumerable<K>.GetEnumerator()
			{ return new Enumerator(this.kdictionary); }

			IEnumerator IEnumerable.GetEnumerator()
			{ return new Enumerator(this.kdictionary); }

			// Properties
			public int Count
			{ get { return this.kdictionary.Count; } }

			// Nested Types
			[Builtin]
			public struct Enumerator : IEnumerator<K>, IDisposable, IEnumerator
			{
				private Dictionary<K, V> dictionary;

				private int index;
				
				internal Enumerator(Dictionary<K, V> dictionary)
				{
					this.dictionary = dictionary;
					this.index = -1;
				}

				public void Dispose()
				{ ;}

				[EnumeratorAdvance]
				public bool MoveNext()
				{
					if(this.index < this.dictionary.capacity)
						this.index++;

					while(this.index < this.dictionary.capacity)
					{
						if(this.dictionary.GetHashAndValidForIndex(this.index) >= 0)
							return true;

						this.index++;
					}

					return false;
				}

				public K Current
				{
 					[EnumeratorGetterDictionaryKeys]
					get { return this.dictionary.GetValueAtIndex(this.index).Key; } 
				}

				object IEnumerator.Current
				{ get { return this.dictionary.GetValueAtIndex(this.index).Key; } }

				void IEnumerator.Reset()
				{ this.index = -1; }
			}
		}

		[Builtin]
		public sealed class ValueCollection : ICollection<V>, IEnumerable<V>, ICollection, IEnumerable
		{
			// Fields
			private Dictionary<K, V> vdictionary;

			// Methods
			public ValueCollection(Dictionary<K, V> dictionary)
			{ this.vdictionary = dictionary; }

			public void CopyTo(V[] array, int index)
			{
				Enumerator ev = new Enumerator(this.vdictionary);
				int j = index;

				while(ev.MoveNext())
					array[j++] = ev.Current;
			}

			public Enumerator GetEnumerator()
			{ return new Enumerator(this.vdictionary); }

			void ICollection<V>.Add(V item)
			{ Environment.Exit(1); }

			void ICollection<V>.Clear()
			{ Environment.Exit(1); }

			bool ICollection<V>.Contains(V item)
			{ return this.vdictionary.ContainsValue(item); }

			bool ICollection<V>.Remove(V item)
			{
				Environment.Exit(1);
				return false;
			}

			IEnumerator<V> IEnumerable<V>.GetEnumerator()
			{ return new Enumerator(this.vdictionary); }

			IEnumerator IEnumerable.GetEnumerator()
			{return new Enumerator(this.vdictionary);}

			// Properties
			public int Count
			{ get { return this.vdictionary.Count; } }

			// Nested Types
			[Builtin]
			public struct Enumerator : IEnumerator<V>, IDisposable, IEnumerator
			{
				private Dictionary<K, V> dictionary;

				private int index;
				
				internal Enumerator(Dictionary<K, V> dictionary)
				{
					this.dictionary = dictionary;
					this.index = -1;
				}

				public void Dispose()
				{ ;}

				[EnumeratorAdvance]
				public bool MoveNext()
				{
					if(this.index < this.dictionary.capacity)
						this.index++;

					while(this.index < this.dictionary.capacity)
					{
						if(this.dictionary.GetHashAndValidForIndex(this.index) >= 0)
							return true;

						this.index++;
					}

					return false;
				}

				public V Current
				{
					[EnumeratorGetterDictionaryValues]
					get { return this.dictionary.GetValueAtIndex(this.index).Value; } 
				}

				object IEnumerator.Current
				{ get { return this.dictionary.GetValueAtIndex(this.index).Value; } }

				void IEnumerator.Reset()
				{ this.index = -1; }
			}
		}
	}
}

#pragma warning restore 0649
#pragma warning restore 0169
